import os
import sys
import time
import traceback
from datetime import datetime

import logzero
from logzero import logger
from tqdm import tqdm
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException

from config import REPORT_ERROR_COLLECTION_NAME, SCREENSHOT_PATH
from utils import open_driver, track_alert, get_mongo_collection, record_run_status

COLLECTION_DETAIL = 'bilibili_fanju_detail'
COLLECTION_FEED = 'bilibili_fanju_detail_feed'
current_module = os.path.splitext(os.path.basename(__file__))[0]
logzero.logfile(f"/tmp/{current_module}.log", maxBytes=30_000_000, backupCount=3, encoding='utf-8')

collection_feed_db = get_mongo_collection(COLLECTION_FEED)
collection_detail_db = get_mongo_collection(COLLECTION_DETAIL)
error_db = get_mongo_collection(REPORT_ERROR_COLLECTION_NAME)

insert_count = 0


@record_run_status(current_module)
def spider(from_season_id):
    fanju_list = collection_feed_db.find(no_cursor_timeout=True)
    if from_season_id:
        need_skip = True
    else:
        need_skip = False
    is_skiped = False
    with open_driver() as driver:
        with track_alert(driver):
            for fanju in tqdm(fanju_list):
                logger.debug('*' * 50)
                season_id = fanju['season_id']
                try:
                    if need_skip and not is_skiped:
                        if from_season_id == season_id:
                            is_skiped = True
                            logger.info(f'从{from_season_id}开始')
                        else:
                            logger.debug(f'跳过{season_id}')
                            continue
                    data = handle_detail(driver, season_id)
                    data = handle_episodes(driver, data)
                    store_data(data, season_id)
                except (NoSuchElementException, StaleElementReferenceException) as e:
                    handle_exception(driver, e, season_id)
                else:
                    delete_error(season_id)

            fanju_list.close()
            logger.info('完成')
            return insert_count


def handle_detail(driver, season_id):
    """
    处理详情页
    :param driver:
    :param season_id:
    :return: 单条数据
    """
    data = {'season_id': season_id, 'desp': '', 'tags': [], 'episodes': []}
    index_url = f'https://bangumi.bilibili.com/anime/{season_id}'
    driver.get(index_url)
    logger.info(f'访问 {index_url}')
    time.sleep(3)
    tags_ele = driver.find_elements_by_css_selector('div.b-head>a>span')
    for tag_ele in tags_ele:
        tag = tag_ele.text
        data['tags'].append(tag)
    desp = driver.find_element_by_css_selector('div.info-desc').text
    data['desp'] = desp
    return data


def handle_episodes(driver, data):
    """
    处理剧集
    :param driver:
    :param data:
    :return:
    """
    page = 1
    while True:
        episodes_ele = driver.find_elements_by_css_selector(
            f'div.complete-list>div.video-slider-list-wrapper>div.slider-part-wrapper>ul:nth-child({page})>li')
        for episode_ele in episodes_ele:
            episode_id = episode_ele.get_attribute('data-episode-id')
            episode_href = episode_ele.find_element_by_css_selector('a').get_attribute('href')
            episode_img = episode_ele.find_element_by_css_selector('div.img-wrp>img').get_attribute(
                'src')
            episode_num = episode_ele.find_element_by_css_selector('div.text-wrp-num-content').text
            episode_title = episode_ele.find_element_by_css_selector('div.text-wrp-title').text
            data['episodes'].append(
                {"episode_id": episode_id, 'episode_href': episode_href, 'episode_img': episode_img,
                 'episode_num': episode_num, 'episode_title': episode_title})
        next_page_ele = driver.find_elements_by_css_selector(
            f'div.complete-list>div.video-slider-list-wrapper>div.slider-part-wrapper>ul:nth-child({page})>div.nextpage')
        if next_page_ele:
            time.sleep(1)
            page += 1
            logger.info(f'翻页{page}')
            next_page_ele[0].click()
            time.sleep(1)
        else:
            break
    return data


def store_data(data, season_id):
    global insert_count
    old_record = collection_detail_db.find_one({'season_id': season_id})
    if old_record:
        logger.info(f'{season_id} 已经存储，现在更新')
        collection_detail_db.update(old_record, {'$set': data})
    else:
        logger.info(f'{season_id}不存在，现在插入')
        logger.info(data)
        collection_detail_db.insert_one(data)
        insert_count += 1


def handle_exception(driver, e, season_id):
    driver.get_screenshot_as_file(
        f"{SCREENSHOT_PATH}/{COLLECTION_DETAIL}_{datetime.now().strftime('%Y-%m-%d %H %M %S')}.png")
    logger.error(e)
    logger.error(traceback.format_exc())
    error_record_condition = {'desp': COLLECTION_DETAIL, 'season_id': season_id}
    error_record = error_db.find_one(error_record_condition)
    if not error_record:
        error_db.insert_one(
            {'desp': COLLECTION_DETAIL, 'season_id': season_id, 'e': e,
             'e_traceback': traceback.format_exc(), 'update_time': datetime.now()})


def delete_error(season_id):
    collection_feed_db.remove({'season_id': season_id})
    error_record_condition = {'desp': COLLECTION_DETAIL, 'season_id': season_id}
    error_record = error_db.find_one(error_record_condition)
    if error_record:
        error_db.delete_one(error_record_condition)
        logger.info('删掉异常记录')


if __name__ == '__main__':
    """
    第一个参数表示从哪个season_id开始爬，不传递直接从头爬
    """
    from_season_id = sys.argv[1] if len(sys.argv) == 2 else None
    spider(from_season_id)
